package site.registry;

import client.Identifier;
import client.Information;
import com.Ostermiller.util.Base64;
import database.ConnectionDB;
import database.DatabaseMysql;
import database.DatabaseOperationsIdentifiers;
import database.DatabaseOperationsUsers;
import security.SealedObj;
import security.SealedObjAES;
import security.Signature;
import security.SignatureSHA1;
import security.MessageDigestSHA1;
import utils.EmailUtils;
import utils.ObjectUtils;
import utils.SynchronizedUtils;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.*;
import javax.servlet.http.*;
import utils.SqlInjectionUtils;



public class HttpsRequest extends HttpServlet {



    private String cipherPassword;
    private String databaseHost;
    private String databaseName;
    private String databasePassword;
    private String databaseUser;
    private String signaturePassword;



    @Override
    public void init(ServletConfig config)
            throws ServletException {

        super.init(config);

        ServletContext context = getServletContext();
        databaseHost      = context.getInitParameter("DatabaseHost");
        databaseName      = context.getInitParameter("DatabaseName");
        databasePassword  = context.getInitParameter("DatabasePassword");
        databaseUser      = context.getInitParameter("DatabaseUser");
        cipherPassword    = context.getInitParameter("CipherPassword");
        signaturePassword = context.getInitParameter("SignaturePassword");
    }


    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        long idThread = Thread.currentThread().getId(); 

        System.out.println("("+idThread+")Setup - ini  process request (" + Calendar.getInstance().getTime().toString() + ")");

        boolean isValidate = validation(request.getParameter("email"), request.getParameter("password"),
                Boolean.valueOf(request.getParameter("new-user")), request.getParameter("name"));

        if (isValidate) {

            System.out.println("("+idThread+")Setup - email and password are validated");

            boolean                         newUser                       = Boolean.valueOf(request.getParameter("new-user"));
           ConnectionDB              connectionDB              = null;
           ServletOutputStream   out                                 = null;

            try {

                response.setContentType("application/octet-stream;charset=UTF-8");

                connectionDB = new DatabaseMysql(databaseHost, databaseUser, databasePassword,databaseName).getConnection();
                DatabaseOperationsUsers operationsUsers = new DatabaseOperationsUsers(connectionDB);
                DatabaseOperationsIdentifiers operationsIdentifiers = new DatabaseOperationsIdentifiers(connectionDB);

                Boolean accessSync       = SynchronizedUtils.getAccessSynch();
                boolean createIdentifier = false;
                String passwordHashBase64  = Base64.encodeToString(new MessageDigestSHA1().digest(request.getParameter("password")));
                int        id         =  new Random().nextInt();
                String zipCode;
                String location;

                synchronized (accessSync)
                {
                    System.out.println("("+idThread+")\tini synchronized (accessSync)");
                    System.out.println("("+idThread+")\tUser email: "+request.getParameter("email"));

                    if (newUser)
                    {
                        if (operationsUsers.existsUser(request.getParameter("email")))
                        {
                            System.out.println("("+idThread+")\tSetup - email is already  used");
                            response.setHeader("status-code", String.valueOf(response.SC_UNAUTHORIZED));
                        }
                        else
                        {
                            System.out.println("("+idThread+")\tSetup - new email");
                            zipCode = SqlInjectionUtils.cleanString(request.getParameter("zipcode")).replace('-',' ');
                            location = SqlInjectionUtils.cleanString(request.getParameter("location")).toLowerCase();
                            operationsUsers.insertUser(request.getParameter("email"), passwordHashBase64,
                                    SqlInjectionUtils.cleanString(request.getParameter("name")),zipCode,location);

                            if(!operationsIdentifiers.existsIdentifier(request.getParameter("email")))
                            {
                                 System.out.println("("+idThread+")\tSetup - create new Identifier in database");
                                 operationsIdentifiers.insertIdentifier(request.getParameter("email"),id);
                            }
                            else
                            {
                                System.out.println("("+idThread+")\tSetup - set a new Identifier in database");
                                operationsIdentifiers.setIdentifierId(request.getParameter("email"), id);
                                operationsUsers.setZipcodeLocationtUser(request.getParameter("email"), zipCode,location);
                            }
                            
                            createIdentifier = true;
                        }
                    }
                    else
                    {
                        if (operationsUsers.verifyPassword(request.getParameter("email"), passwordHashBase64))
                        {
                            System.out.println("("+idThread+")\tSetup - it will be set a new Identifier");

                           
                            zipCode = SqlInjectionUtils.cleanString(request.getParameter("zipcode")).replace('-',' ');
                            location = SqlInjectionUtils.cleanString(request.getParameter("location")).toLowerCase();
                            operationsIdentifiers.setIdentifierId(request.getParameter("email"), id);
                            operationsUsers.setZipcodeLocationtUser(request.getParameter("email"),zipCode, location);
                            createIdentifier = true;
                        }
                        else
                        {
                            System.out.println("("+idThread+")\tSetup - invalid password");
                            response.setHeader("status-code", String.valueOf(response.SC_UNAUTHORIZED));
                        }
                    }
                    System.out.println("("+idThread+")\tend synchronized (accessSync)");
                }

                if (createIdentifier) {

                     System.out.println("("+idThread+")Setup - create Identifier");

                    response.setHeader("status-code", String.valueOf(response.SC_OK));
                    out = response.getOutputStream();
                  
                    Identifier identifier = createIdentifier(request.getParameter("email"), id);

                    byte[] bytesIdentifier = ObjectUtils.toBytes(identifier);
                    out.write(bytesIdentifier);
                    out.flush();
                }
            }
            catch (InvalidKeyException e) {
                Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE,"InvalidKeyException"+e.getLocalizedMessage());
                response.setHeader("status-code", String.valueOf(response.SC_INTERNAL_SERVER_ERROR));
            }
            catch (GeneralSecurityException e) {
                Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE,"GeneralSecurityException: "+e.getLocalizedMessage());
                response.setHeader("status-code", String.valueOf(response.SC_INTERNAL_SERVER_ERROR));
            }
            catch (SQLException e) {
                Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE,"SQLException: "+e.getLocalizedMessage());
                response.setHeader("status-code", String.valueOf(response.SC_INTERNAL_SERVER_ERROR));
            }
            finally {
                if (connectionDB != null) {
                    try {

                        connectionDB.close();
                    } catch (SQLException ex) {}
                }

                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException ex) {}
                }
            }
        }else{
            System.out.println("("+idThread+")Setup - email and password are invalidated");
        }

        System.out.println("("+idThread+")Setup - end  process request (" + Calendar.getInstance().getTime().toString() + ")");
        System.out.println();
    }


    private Identifier createIdentifier(String email, int id)
            throws InvalidKeyException, GeneralSecurityException, IOException {
        SealedObj   sealed     = new SealedObjAES(cipherPassword.getBytes("UTF-8"));
        Signature   signature  = new SignatureSHA1(signaturePassword.getBytes("UTF-8"));
        Information info       = new Information(email, id);
        Identifier  identifier = new Identifier(sealed.getSealedObj(info), signature.getSignature(info));

        return identifier;
    }


    private boolean validation(String email, String password, boolean newUser, String name) {
                return (email != null) && (password != null) && (email.length() > 0) && (email.length() <= 50)
               && EmailUtils.verification(email) && (password.length() >0) && (password.length() <= 30)
               && (newUser==true ? name.length() >0 : true);
    }

    
   
    // netbeans code
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">

    /**
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     */
    public String getServletInfo() {
        return "Short description";
    }

    // </editor-fold>

    
}

